import cv2 as cv
import sys
import os
from python_ai.common.xcommon import *
import matplotlib.pyplot as plt
import numpy as np
import time
import datetime


def my_show_img(img, title="no title", trans=None, **kwargs):
    global spn
    spn += 1
    plt.subplot(spr, spc, spn)
    if trans is not None:
        img = trans(img)
    plt.imshow(img, **kwargs)
    plt.axis('off')
    plt.title(title)


img_dir = '../../../../../large_data/CV2/lesson/Day06'
img_name = 'hammer.jpg'
# img_dir = '../../../../../large_data/pic'
# img_name = 'DSC05039.JPG'
# img_name = 'DSC05022_1.JPG'
# img_name = 'dog.jpg'
# img_name = 'dog_bird.jpg'
img_path = os.path.join(img_dir, img_name)

spr = 2
spc = 4
spn = 0
plt.figure(figsize=[14, 10])

sep('load')
img = cv.imread(img_path, cv.IMREAD_GRAYSCALE)
# img = cv.resize(img, None, fx=0.1, fy=0.1, interpolation=cv.INTER_CUBIC)
print('original shape', img.shape)
H, W = img.shape
H2 = (H - 1) // 2
W2 = (W - 1) // 2
# my_show_img(img, 'original', cmap='gray')

# bin
ret, thresh = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
my_show_img(thresh, 'threshold', cmap='gray')


def draw_contour(retr_type, type):
    contours, hierarchy = cv.findContours(thresh, retr_type, cv.CHAIN_APPROX_SIMPLE)
    black = np.zeros((H, W), dtype=np.uint8)
    black = cv.cvtColor(black, cv.COLOR_GRAY2BGR)
    res = cv.drawContours(black, contours, -1, (0, 255, 0), 1)
    my_show_img(res, 'contours ' + type, lambda x: cv.cvtColor(x, cv.COLOR_BGR2RGB))
    return contours


contours_tree = draw_contour(cv.RETR_TREE, 'tree')
controus_externel = draw_contour(cv.RETR_EXTERNAL, 'external')


def find_longest_c(contours):
    max_len = 0
    max_i = -1
    for i, c in enumerate(contours):
        lenc = len(c)
        if lenc > max_len:
            max_len = lenc
            max_i = i
    return max_i


black = np.zeros((H, W), dtype=np.uint8)
black = cv.cvtColor(black, cv.COLOR_GRAY2BGR)
i_tree = find_longest_c(contours_tree)
res = cv.drawContours(black, [contours_tree[i_tree]], 0, (0, 255, 0), 2)
my_show_img(res, 'tree longest', lambda x: cv.cvtColor(x, cv.COLOR_BGR2RGB))

# longest contour in externel mode
black = np.zeros((H, W), dtype=np.uint8)
black = cv.cvtColor(black, cv.COLOR_GRAY2BGR)
i_external = find_longest_c(controus_externel)
c = controus_externel[i_external]
res = cv.drawContours(black, [c], 0, (255, 255, 255), 2)

# bounding rect
x, y, w, h = cv.boundingRect(c)
cv.rectangle(res, (x, y), (x + w, y + h), (0, 255, 0), 2)

# rotated min rect
rotatedRect = cv.minAreaRect(c)
box = cv.boxPoints(rotatedRect)
box = box.astype(np.int32)
cv.drawContours(res, [box], 0, (0, 0, 255), 2)

# min enclosing circle
(x, y), r = cv.minEnclosingCircle(c)
cv.circle(res, np.int32((x, y)), int(r), (255, 0, 0), 2)

# min enclosing triangle
sep('min enclosing triangle')
ret, triangle = cv.minEnclosingTriangle(c)
print(triangle)
# triangle = np.squeeze(triangle)
triangle = np.int32(triangle)
print(triangle)
# ATTENTION Below is unnecessary, cv.polylines can draw on negative coordinates.
# print('W, H: ', W, H)
# LEFT_PADDING = 65
# BOTTOM_PADDING = 120
# triangle[:, :, 0] += LEFT_PADDING
# print(triangle)
# # triangle[:, :, 1] += BOTTOM_PADDING
# # print(triangle)
# padding = np.zeros((H, LEFT_PADDING, 3), dtype=np.uint8)
# res = np.concatenate((padding, res), axis=1)
# padding = np.zeros((BOTTOM_PADDING, W + LEFT_PADDING, 3), dtype=np.uint8)
# res = np.concatenate((res, padding), axis=0)
# print('W, H: ', res.shape)
cv.polylines(res, [triangle], True, (0, 255, 255), 2)

my_show_img(res, 'external longest', lambda x: cv.cvtColor(x, cv.COLOR_BGR2RGB))

# hull
black = np.zeros((H, W), dtype=np.uint8)
black = cv.cvtColor(black, cv.COLOR_GRAY2BGR)
hull = cv.convexHull(c)
cv.drawContours(black, [c], 0, (0, 255, 0), 2)
cv.drawContours(black, [hull], 0, (0, 0, 255), 2)
my_show_img(black, 'convex hull', lambda x: cv.cvtColor(x, cv.COLOR_BGR2RGB))

# approx ploy discrete polylines
black = np.zeros((H, W), dtype=np.uint8)
black = cv.cvtColor(black, cv.COLOR_GRAY2BGR)
c_len = cv.arcLength(c, True)
epsilon = 1e-2 * c_len
approx = cv.approxPolyDP(c, epsilon, True)
cv.drawContours(black, [c], 0, (0, 255, 0), 2)
cv.drawContours(black, [approx], 0, (0, 0, 255), 2)
my_show_img(black, 'approxPolyDP', lambda x: cv.cvtColor(x, cv.COLOR_BGR2RGB))

